package com.zb.zeus.common.redis.service.impl;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;

import com.zb.zeus.common.redis.service.IRedisComponent;

import lombok.extern.slf4j.Slf4j;


/**
 * RedisLockService
 *
 * @author lf
 * @date 2021/5/26
 */
@Component
@Slf4j
public class RedisLockComponent implements IRedisComponent {

    private static final String LOCK_SCRIPT =
            "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then  " +
            "    return redis.call('expire',KEYS[1],ARGV[2])  " +
            "else " +
            " return 0 " +
            "end";

    private static final String UNLOCK_SCRIPT =
            "if redis.call('get', KEYS[1]) == ARGV[1] then " +
            "   return redis.call('del', KEYS[1]) " +
            "else " +
            "   return 0 " +
            "end";

    private static final Long SUCCESS = 1L;


    @Autowired
    private StringRedisTemplate strRedisTemplate;



    @Override
    public String getKeyPre() {
        return "rlock:";
    }


    /**
     * 加锁
     * @param key
     * @param value
     * @param expire 单位s
     * @return
     */
    public boolean lock(String key, String value, long expire){
        key = getKeyPre()+key;
//        log.info("[RedisLockService # lock] key = " +key + " value = " +value + " expire = "+expire);
        RedisScript<Long> redisScript = new DefaultRedisScript<>(LOCK_SCRIPT, Long.class);
        List<String> keys = new ArrayList<>(1);
        keys.add(key);
        Long result = (Long) strRedisTemplate.execute(redisScript, keys, value, String.valueOf(expire));
        boolean res = SUCCESS.equals(result);
//        log.info("[RedisLockService # lock] key = " +key + " value = " +value +  " res = " + res);
        return res;
    }

    /**
     * 是否锁住了
     * @param key
     * @return
     */
    public Boolean isLock(String key){
        key = getKeyPre()+key;
        return strRedisTemplate.hasKey(key);
    }


    /**
     * 解锁
     * @param key
     * @param value
     * @return
     */
    public boolean unlock(String key, String value){
        key = getKeyPre()+key;
//        log.info("[RedisLockService # unlock] key = " +key + " value = " +value );
        RedisScript<Long> redisScript = new DefaultRedisScript<>(UNLOCK_SCRIPT, Long.class);

        List<String> keys = new ArrayList<>(1);
        keys.add(key);

        boolean res = false;
        try {
            Long result = (Long) strRedisTemplate.execute(redisScript, keys, value);
            res = SUCCESS.equals(result);
        } catch (Exception e) {
            res = false;
            e.printStackTrace();
        }finally {
//            log.info("[RedisLockService # unlock] key = " +key + " value = " +value + " res = " + res);
        }
        return res;
    }
}
